package org.peterbjornx.graphics.jogl.callqueue;

import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;

/**
 * Represents a method call
 */
public class MethodCall {

    public Method myMethod;
    public Object[] myArgs;
    public Object instance;
    public static Class integer;
    public static Class bool;
    public static Class floatz;
    public static Class duble;
    static {
        try {
            integer = Class.forName("java.lang.Integer");
        } catch (ClassNotFoundException e) {
            System.err.println("[MethodCall] java.lang.Integer not found, Please check your JAVA API.");
        }
        try {
            bool = Class.forName("java.lang.Boolean");
        } catch (ClassNotFoundException e) {
            System.err.println("[MethodCall] java.lang.Boolean not found, Please check your JAVA API.");
        }
        try {
            floatz = Class.forName("java.lang.Float");
        } catch (ClassNotFoundException e) {
            System.err.println("[MethodCall] java.lang.Float not found, Please check your JAVA API.");
        }
        try {
            duble = Class.forName("java.lang.Double");
        } catch (ClassNotFoundException e) {
            System.err.println("[MethodCall] java.lang.Double not found, Please check your JAVA API.");
        }
    }

    /**
     * We want to be able to use primary types.
     * @param o The object
     * @return The type for the object
     */
    public static Class classForObject(Object o)
    {
        if (o.getClass().equals(integer))
            return int.class;
        else if (o.getClass().equals(bool))
            return boolean.class;
        else if (o.getClass().equals(floatz))
            return float.class;
        else if (o.getClass().equals(duble))
            return double.class;
        else
            return o.getClass();
    }

    public MethodCall(Object instance,String name,Object[] args)
    {
        Class c;
        if (instance instanceof Class)
            c = (Class) instance;
        else
            c = instance.getClass();
        Class[] types = null;
        try {
            if (args != null)
            {
                types = new Class[args.length];
                for (int i = 0; i < args.length; i++)
                types[i] = classForObject(args[i]);
            }
            myMethod = c.getDeclaredMethod(name,types);
        } catch (NoSuchMethodException e) {
            System.err.println("[MethodCall] No such method ezists :"+name + " " + ( ( args == null ) ? "null" : args.length ) );
        }
        myArgs = args;
        this.instance = instance;
    }

    public Object doCall()
    {
        try {
            return myMethod.invoke(instance,myArgs);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            System.err.println("[MethodCall] Wrong number of arguments for :"+myMethod.getName() + " " + ( ( myArgs == null ) ? "null" :myArgs.length ) );
        }
        return null;
    }

}
